#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/device.h>

/*
	mykeys{
		interrupt-parent = <&gpiof>;
		interrupts = <9 0>,<7 0>, <8 0>; 
		interrupts-name = "key1", "key2", "key3";
		key-gpios = <&gpiof 9 0>, <&gpiof 7 0>, <&gpiof 8 0>;
	};
 */

MODULE_LICENSE("GPL");

typedef struct
{
    const char* m_btnName;
    unsigned int m_btnIrq; // 中断号
    struct timer_list m_btnTimer; // 按键消抖
    struct gpio_desc* m_pinDesc;
}btn_desc_t;

static btn_desc_t btns[3];

static int cnt = 1;

int btn_open_func(struct inode *inode, struct file *filp)
{
	if(--cnt != 0)
    {
		cnt++;
		return -EBUSY;
	}	
	return 0;
}

int btn_release_func(struct inode *inode, struct file *filp)
{
	cnt++;
	return 0;
}

ssize_t btn_read_func (struct file *filp, char __user *buf, size_t len, loff_t *offset)
{
	return len;
}

static struct device_node* btnNode;
static dev_t btnDevNum;
static struct cdev* btnCdev;
static struct class* btnClass = NULL;
static struct file_operations btnFops= {
    .owner = THIS_MODULE,
    .open = btn_open_func,
    .read = btn_read_func,
    .release = btn_release_func
};

// 按键触发中断函数
irqreturn_t btn_handle(int irqNum, void* dev)
{
    btn_desc_t* data = (btn_desc_t*)dev;
    mod_timer(&data->m_btnTimer,jiffies + (HZ / 100));
    return IRQ_HANDLED;
}

// 定时器超时触发的函数
void btn_timer_func(struct timer_list* timer)
{
    int state = 0;
    btn_desc_t* data = container_of(timer,btn_desc_t,m_btnTimer);

    state = gpiod_get_value(data->m_pinDesc);
    printk("%s is %s gpio id=%d!\n", data->m_btnName, state?"release": "pressed", desc_to_gpio(data->m_pinDesc));
}

static int __init btn_drv_init(void)
{
    int i = 0;
    btnNode = of_find_node_by_path("mykeys");

    for(;i<ARRAY_SIZE(btns);i++)
    {
        btns[i].m_btnIrq = irq_of_parse_and_map(btnNode,i);// 映射中断号
        of_property_read_string_index(btnNode,"interrupts-name",i,&btns[i].m_btnName);

        request_irq(btns[i].m_btnIrq,btn_handle,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
                    btns[i].m_btnName,&btns[i]);// 中断资源申请

        btns[i].m_pinDesc = gpiod_get_from_of_node(btnNode,"key-gpios",i,GPIOD_IN,btns[i].m_btnName);// gpio资源申请

        timer_setup(&btns[i].m_btnTimer,btn_timer_func,0);// 初始化定时器
    }

    alloc_chrdev_region(&btnDevNum,0,1,"btnsDevNum");// 分配设备号
    btnCdev = cdev_alloc();// 动态分配cdev内存
    cdev_init(btnCdev,&btnFops);// cdev初始化，绑定操作函数
    cdev_add(btnCdev,btnDevNum,1);// 将cdev添加到系统中

    btnClass = class_create(THIS_MODULE,"btnClass");// 创建class
    device_create(btnClass,NULL,btnDevNum,NULL,"myBtnsDev");// 创建设备文件

    return 0;
}

static void __exit btn_drv_exit(void)
{
    int i =0;

    device_destroy(btnClass,btnDevNum);// 销毁设备文件
    class_destroy(btnClass);// 销毁class
    cdev_del(btnCdev);// 清理cdev内存
    unregister_chrdev_region(btnDevNum,1);// 注销设备号

    for(;i<ARRAY_SIZE(btns);i++)
    {
        del_timer(&btns[i].m_btnTimer);// 删除定时器
        gpiod_put(btns[i].m_pinDesc);// 释放gpio资源
        free_irq(btns[i].m_btnIrq,&btns[i]);// 释放irq中断
    }
    
}

module_init(btn_drv_init);
module_exit(btn_drv_exit);
